/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */

package lime2;

import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import sagroup.util.Util;
import lights.interfaces.*;

/**
 * The local manager of a LimeTupleSpace. It receives LocalOps and processes
 * them: LocalOpMgr uses a PriorityScheduler to create the abstraction of two
 * different queues: "operations" and "events"; the events queue receives a
 * higher priority service. <br>
 * Operations model any operation on a LimeTupleSpace. <br>
 * Events model the triggering of weak reactions.
 * 
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini
 */

public class LocalOpMgr extends Thread implements LimeConstants {
	private static Logger logger = Logger.getLogger("lime2.LocalOpMgr");
	static {
		logger.setLevel(Level.ALL);
	}

	// constants for the queues
	private static final int EVENTS_QUEUE = 0;
	private static final int OPERATIONS_QUEUE = 1;
	private static final int PRIORITY_FACTOR = 3;

	// priority scheduler
	private PriorityScheduler pSch;

	// reactor manager
	private LimeTSMgr ltsm;

	// communication manager
	private CommunicationMgr cMgr;

	// registered name
	private String name;

	/**
	 * Constructor method.
	 * 
	 * @param name
	 *            the registered name
	 * @param policy
	 *            of the corresponding tuplespace
	 */
	public LocalOpMgr(String name, byte policy) {
		// creates the priority scheduler
		pSch = new PriorityScheduler(new int[] { PRIORITY_FACTOR, 1 });
		// creates the reactor manager
		ltsm = LimeTSMgr.creatLTSM(name, policy);
		// inializes the communication manager
		cMgr = CommunicationMgr.get();
		// registers the name
		this.name = name;
	}

	/**
	 * Adds a LocalOp to the queue of operations. This method is invoked by
	 * agents (no need to synchronize them since queuing itself provides
	 * synchronization) or by the LocalOpMgr thread (= the code within a
	 * reaction required a LimeTupleSpace operation). The method is re-entrant.
	 * 
	 * @param o
	 *            the LocalOp (= TupleOp or ReactionOp) to add to the queue of
	 *            operations
	 */
	public void postOperation(LocalOp o) {
		// two cases are possible:
		//
		// (1) "postOp" was invoked by the Lime system itself (that is to say,
		// we are within a reaction)
		// (2) "postOp" was invoked by another agent
		//
		// So the discriminant beetween (1) and (2) is the the thread that
		// invoked "postOp" (LocalOpMgr thread or agent
		// thread). In the case of (1) the op is processed immediately, skipping
		// the enqueuing; also no lock is held since
		// it would block the LocalOpMgr thread. We want operations from the
		// LocalOpMgr to be immediately executed (performOp)
		// rather than enqueued (opQueue.add): the code in a reaction listener
		// is executed by the Lime system and it must
		// complete the execution of an operation (= get the result back) before
		// executing the next line of code. Otherwise
		// true sequentiality of operations within the same fragment of code
		// wouldn't be enforced.
		// Blocking operations (in and rd) are not allowed in the code of
		// listeners of strong or weak reactions because of
		// their semantics: they would require to freeze the Lime system itself.
		// An IllegalReactionOperationException must
		// be thrown instead.
		// The other operations (inp, ing, rdp, rdg, out, outg,
		// addStrongReaction, removeStrongReaction) do not generate
		// semantical problems
		if (isLimeSystem())
			performOp(o);
		else
			// if it is an agent that wants to execute this local operation (=
			// posted it), the agent is blocked until the lock
			// is released. It is a system thread that releases the lock (if it
			// is a non blocking operation, the system releases
			// the lock as soon as the result of the operation is ready; if it
			// is a blocking operation then a system reaction is
			// registered within the Reactor. The listener within the system
			// reaction will release the lock on firing.
			// This listener is executed by the LocalOpMgr, so it is the
			// LocalOpMgr again). Class Result carries the result of
			// the operation back to the agent through the (method of the)
			// LimeTupleSpace (addStrongReaction, rdp, ing, out..)
			// Please note that if there is no blocked thread, the release of
			// the corresponding lock will do nothing
			synchronized (o.result.lock) {
				// why we need "synchronized(lock)" ? because we must protect
				// against the bad interleaving in which the LocalOpMgr
				// thread releases the lock before the agent held it. In the
				// case the agent would wait forever
				pSch.schedule(OPERATIONS_QUEUE, o);
				o.result.lock.hold();
			}
	}

	/**
	 * Adds a LocalOp to the queue of events. This method is invoked only by the
	 * Lime system.
	 * 
	 * @param o
	 *            the LocalOp (= WeakOp) to add to the queue of events
	 */
	void postEvent(LocalOp o) {
		pSch.schedule(EVENTS_QUEUE, o);
	}

	/**
	 * Continuously waits for a LocalOp to be posted to the internal queues and
	 * processes it; the events queue gets a higher priority service.
	 */
	public void run() {
		for (;;)
			performOp((LocalOp) pSch.serve());
	}

	// processes a LocalOp
	private void performOp(LocalOp o) {
		// are we within a reaction ?
		boolean recursive = ltsm.isWithinReaction();

		// is this host engaged ? (.. we cannot allow remote operations
		// otherwise)
		boolean engaged = LimeServer.getServer().isEngaged();

		// TupleOp
		if (o instanceof TupleOp) {
			TupleOp to = (TupleOp) o;
			Location target = null;
			if (Util.isWriteOp(to.type)) {
				target = LimeWrapper.getDest(to.tuples[0]);
			} else {
				target = LimeWrapper.getCur(to.tuples[0]);
			}
			if (!engaged && !target.isHere())
				throw new NotEngagedException("this host is not engaged");

			switch (to.type) {
			case RD:
				// we can't allow a blocking operation to be executed within a
				// strong or weak reaction
				if (recursive)
					throw new IllegalReactionOperationException("rd");
				performRD(to, target, recursive);
				break;
			case RDP:
				performRDP(to, target, recursive);
				break;
			case RDG:
				performRDG(to, target, recursive);
				break;
			case IN:
				// we can't allow a blocking operation to be executed within a
				// strong or weak reaction
				if (recursive)
					throw new IllegalReactionOperationException("in");
				performIN(to, target, recursive);
				break;
			case INP:
				performINP(to, target, recursive);
				break;
			case ING:
				performING(to, target, recursive);
				break;
			case OUT:
				performOUT(to, target, recursive);
				break;
			case OUTG:
				TupleOp[] tos = OpUtils.separateT(to);
				if (!engaged && tos.length > 1)
					throw new IllegalArgumentException(
							"this host is not engaged");
				performOUTG(to, tos, target, recursive);
				break;
			case OUTM:
				performOUTM(to, to.targets, recursive);
				break;
			case UPDATE:
				performUPDATE(to, target, recursive);
				break;
			case UPDATE_REPLICA:
				perforUPDATE_REPLICA(to, target, recursive);
				break;
			}
		}
		// end TupleOp
		// ReactionOp
		else if (o instanceof ReactionOp) {
			ReactionOp ro = (ReactionOp) o;
			switch (ro.type) {
			case INSTALL_STRONG: {
				// strong reactions are only local
				ro.result.set(ltsm.registerStrong(ro.rea, ltsm
						.nextPureStrongRID(ro.rea.length)));
				ro.result.lock.release();
			}
				break;
			case REMOVE_STRONG: {
				// strong reactions can be only local
				ro.result.set(ltsm.deregisterStrong(ro.ids));
				ro.result.lock.release();
			}
				break;
			case INSTALL_WEAK: {
				performInstallWeak(ro, recursive, engaged);
			}
				break;
			case REMOVE_WEAK:
				performRemoveWeak(ro, recursive, engaged);
				break;
			}
		}
		// end ReactionOp
		// WeakOp
		else if (o instanceof WeakOp) {
			WeakOp wo = (WeakOp) o;
			// it is not necessary to check type since there is only one type of
			// WeakOp
			ltsm.fireWeak(wo.wrid, wo.wevent);
		}
		// end WeakOp
	}

	private void perforUPDATE_REPLICA(TupleOp to, Location target,
			boolean recursive) {
		// -------------
		// ONLY LOCAL CASE IS ILLEGAL
		// -------------
		if (!target.isHere())
			throw new IllegalArgumentException(
					"Remote update replica is illegal");
		to.result.set(ltsm.doUpdate(to.tuples[0], to.tuples[1]));
		to.result.lock.release();
	}

	private void performUPDATE(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			to.result.set(ltsm.doUpdate(to.tuples[0], to.tuples[1]));
			to.result.lock.release();
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			throw new IllegalArgumentException(
					"Update cannot be performed on unspecified target");
		}
		// -------------
		// REMOTE CASE
		// -------------
		else
			cMgr.postOp(new RemTupleOp(REM_UPDATE_UNI, OPEN, name, target
					.getID(), to), recursive);

	}

	/**
	 * @param ro
	 * @param recursive
	 * @param engaged
	 * @author Xing Jiankuan
	 */
	private void performRemoveWeak(ReactionOp ro, boolean recursive,
			boolean engaged) {
		// generates boolean
		boolean[] ret = new boolean[ro.ids.length];
		for (int i = 0; i < ro.ids.length; i++)
			ret[i] = false;
		ro.result.set(ret);

		// childred ops
		Scrambled scb = OpUtils.separateI(ro, name);
		ReactionOp[] ros = scb.getReactionOp();
		int[][] scrambld = scb.getScrambled();
		ro.result.lock.setClicks(ros.length);

		Location target = ros[0].ids[0].getTarget();
		boolean clickLocal = false;
		int j = 0;

		// --------------
		// INVALID CASE
		// --------------
		if (target.isInvalid()) {
			ro.result.lock.release();
			j++;
		}

		// ------------
		// LOCAL CASE
		// ------------
		if (j < ros.length) {
			target = ros[j].ids[0].getTarget();
			if (!engaged && (!target.isHere() || ros.length - j > 1))
				throw new NotEngagedException("this host is not engaged");

			if (target.isHere()) {
				clickLocal = true;
				boolean[] b1 = ltsm.deregisterWeak(ros[j].ids);
				boolean[] b2 = ltsm.deregisterStrong(ros[j].ids);
				for (int i = 0; i < ros[j].ids.length; i++)
					if (b1[i] && b2[i])
						ret[scrambld[j][i]] = true;
				j++;
			}
		}

		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		if (j < ros.length) {
			target = ros[j].ids[0].getTarget();

			if (target.isUnspecified()) {
				clickLocal = true;
				boolean[] b1 = ltsm.deregisterWeak(ros[j].ids);
				// .. but the strong reaction could have fired (=
				// uninstalled) and the weak one not yet (= the posted
				// WeakOp has still to be processed)
				boolean[] b2 = ltsm.deregisterStrong(ros[j].ids);
				for (int i = 0; i < ros[j].ids.length; i++)
					if (b1[i] && b2[i])
						ret[scrambld[j][i]] = true;
				cMgr.postOp(new RemReactionOp(REM_REMOVE_MULTI, OPEN, name,
						ros[j]), recursive);
				j++;
			}
		}

		if (clickLocal)
			ro.result.lock.release();

		// -------------
		// REMOTE CASE
		// -------------
		for (; j < ros.length; j++) {
			target = ros[j].ids[0].getTarget();
			boolean[] b = ltsm.deregisterWeak(ros[j].ids);
			for (int i = 0; i < ros[j].ids.length; i++)
				if (b[i])
					ret[scrambld[j][i]] = true;
			cMgr.postOp(new RemReactionOp(REM_REMOVE_UNI, OPEN, name, target
					.getID(), ros[j]), recursive);
		}
	}

	/**
	 * @param ro
	 * @param recursive
	 * @param engaged
	 * @author Xing Jiankuan
	 */
	private void performInstallWeak(ReactionOp ro, boolean recursive,
			boolean engaged) {
		// generates IDs
		ReactionID[] ret = new ReactionID[ro.rea.length];
		ret = ltsm.nextStrongRID(ro.rea.length);
		ro.result.set(ret);

		// changes the original weak reactions into SystemRemoteWeakL
		Reaction[] tmp = new Reaction[ro.rea.length];
		for (int i = 0; i < ro.rea.length; i++)
			tmp[i] = new Reaction(ro.rea[i].getMode(), ro.rea[i].getTemplate(),
					new SystemRemoteWeakL(ro.rea[i], ret[i], ltsm));
		ro.rea = tmp;

		// children ops
		Scrambled scb = OpUtils.separateR(ro);
		ReactionOp[] ros = scb.getReactionOp();
		int[][] scrambld = scb.getScrambled();
		ro.result.lock.setClicks(ros.length);

		// childred ids
		for (int z1 = 0; z1 < ros.length; z1++) {
			ros[z1].ids = new ReactionID[ros[z1].rea.length];
			for (int z2 = 0; z2 < ros[z1].rea.length; z2++)
				ros[z1].ids[z2] = ret[scrambld[z1][z2]];
		}

		Location target = LimeWrapper.getCur(ros[0].rea[0].getTemplate());
		if (!engaged && (!target.isHere() || ros.length > 1))
			throw new NotEngagedException("this host is not engaged");
		boolean clickLoc = false;
		int j = 0;

		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			clickLoc = true;
			Reaction[] rL = new Reaction[ros[j].rea.length];
			for (int i = 0; i < ros[j].rea.length; i++)
				rL[i] = new Reaction(ros[j].rea[i].getMode(), ros[j].rea[i]
						.getTemplate(),
						new SystemLocalWeak(this, ros[j].ids[i]));

			ReactionID[] iW = ltsm.createWeakRID(ros[j].ids, rL);
			for (int i = 0; i < ros[j].rea.length; i++)
				ret[scrambld[j][i]] = iW[i];

			ltsm.registerWeak(ros[j].rea, iW);
			ltsm.registerStrong(rL, ros[j].ids);
			j++;
		}
		if (j >= ros.length && clickLoc)
			ro.result.lock.release();

		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		if (j < ros.length) {
			target = LimeWrapper.getCur(ros[j].rea[0].getTemplate());

			if (target.isUnspecified()) {
				clickLoc = true;

				Reaction[] rL = new Reaction[ros[j].rea.length];
				for (int i = 0; i < ros[j].rea.length; i++)
					rL[i] = new Reaction(ros[j].rea[i].getMode(), ros[j].rea[i]
							.getTemplate(), new SystemLocalWeak(this,
							ros[j].ids[i]));
				Reaction[] rR = new Reaction[ros[j].rea.length];
				for (int i = 0; i < ros[j].rea.length; i++)
					rR[i] = new Reaction(ros[j].rea[i].getMode(), ros[j].rea[i]
							.getTemplate(), new SystemRemoteWeakR(REM_EVENTW,
							name, Location.HERE.getID(), ros[j].ids[i]));

				ReactionID[] iW = ltsm.createWeakRID(ros[j].ids, rR);
				for (int i = 0; i < ros[j].rea.length; i++)
					ret[scrambld[j][i]] = iW[i];

				ltsm.registerWeak(ros[j].rea, iW);
				ltsm.registerStrong(rL, ros[j].ids);

				if (clickLoc)
					ro.result.lock.release(); // .. we are finished with
				// the local part

				ros[j].rea = rR;
				cMgr.postOp(new RemReactionOp(REM_INSTALL_MULTI, OPEN, name,
						ros[j]), recursive);
				j++;
			}
		}

		// -------------
		// REMOTE CASE
		// -------------
		for (; j < ros.length; j++) {
			target = LimeWrapper.getCur(ros[j].rea[0].getTemplate());

			Reaction[] rR = new Reaction[ros[j].rea.length];
			for (int i = 0; i < ros[j].rea.length; i++)
				rR[i] = new Reaction(ros[j].rea[i].getMode(), ros[j].rea[i]
						.getTemplate(), new SystemRemoteWeakR(REM_EVENTW, name,
						Location.HERE.getID(), ros[j].ids[i]));

			ReactionID[] iW = ltsm.createWeakRID(ros[j].ids, rR);
			for (int i = 0; i < ros[j].rea.length; i++)
				ret[scrambld[j][i]] = iW[i];

			ltsm.registerWeak(ros[j].rea, iW);

			ros[j].rea = rR;
			cMgr.postOp(new RemReactionOp(REM_INSTALL_UNI, OPEN, name, target
					.getID(), ros[j]), recursive);
		}
	}

	/**
	 * @param to
	 * @param target
	 * @param recursive
	 * @author Xing Jiankuan
	 */
	private void performIN(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			Reaction[] rrd = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemLocalBlocking(ltsm, to)) };
			ltsm.registerStrong(rrd, ltsm.nextPureStrongRID(1));
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			ReactionID[] iS = ltsm.nextStrongRID(1);

			// .. IN requires ability to re-install itself
			SystemRemoteWeakR x = new SystemRemoteWeakR(REM_INW, name,
					Location.HERE.getID(), iS[0]);
			Reaction y = new Reaction(Reaction.ONCE, to.tuples[0], x);
			x.setReRegistration(y);

			Reaction[] RS = new Reaction[] { y };
			Reaction[] LS = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteBlockingLS(IN, iS[0], ltsm,
							to.result)) };
			Reaction[] LW = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteBlockingLW(true, iS[0], ltsm,
							to.result)) };
			ReactionID[] iW = ltsm.createWeakRID(iS, RS);

			ltsm.registerWeak(LW, iW);
			ltsm.registerStrong(LS, iS); // we register LS after LW so
			// that LW will be
			// immediately uninstalled
			// if LS fires

			ReactionOp ro = new ReactionOp(to.type, RS, iS, new Result()); // new
																			// result..
																			// we
																			// don't
																			// want
																			// the
			// older one to be notified
			cMgr.postOp(new RemReactionOp(REM_INSTALL_MULTI, OPEN, name, ro),
					recursive); // recursive is false
		}
		// -------------
		// REMOTE CASE
		// -------------
		else {
			ReactionID[] iS = ltsm.nextStrongRID(1);

			// .. IN requires ability to re-install itself
			SystemRemoteWeakR x = new SystemRemoteWeakR(REM_INW, name,
					Location.HERE.getID(), iS[0]);
			Reaction y = new Reaction(Reaction.ONCE, to.tuples[0], x);
			x.setReRegistration(y);

			Reaction[] RS = new Reaction[] { y };
			Reaction[] LW = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteBlockingLW(false, iS[0],
							ltsm, to.result)) };
			ReactionID[] iW = ltsm.createWeakRID(iS, RS);

			ltsm.registerWeak(LW, iW);

			ReactionOp ro = new ReactionOp(to.type, RS, iS, new Result()); // new
																			// result..
																			// we
																			// don't
																			// want
																			// the
			// older one to be notified
			cMgr.postOp(new RemReactionOp(REM_INSTALL_UNI, OPEN, name, target
					.getID(), ro), recursive); // recursive is
			// false
		}
	}

	/**
	 * @param to
	 *            the original TupleOp
	 * @param tos
	 *            the separated TupleOp each of which has the same target
	 * @param target
	 * @param recursive
	 * @author Xing Jiankuan
	 */
	private void performOUTG(TupleOp to, TupleOp[] tos, Location target,
			boolean recursive) {
		to.result.lock.setClicks(tos.length);

		int j = 0;

		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			ltsm.doWrite(tos[0].tuples);
			to.result.lock.release();
			j++;
		}

		// -------------
		// REMOTE CASE
		// -------------
		for (; j < tos.length; j++) {
			target = LimeWrapper.getDest(tos[j].tuples[0]);
			cMgr.postOp(new RemTupleOp(REM_OUTG, OPEN, name, target.getID(),
					tos[j]), recursive);
		}
	}

	/**
	 * @param to
	 * @param target
	 * @param recursive
	 * @author Xing Jiankuan
	 */
	private void performOUT(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			logger.info(("to write: " + Arrays.toString(to.tuples)));
			ltsm.doWrite(to.tuples);
			to.result.lock.release();
		}
		// -------------
		// REMOTE CASE
		// -------------
		else
			cMgr.postOp(
					new RemTupleOp(REM_OUT, OPEN, name, target.getID(), to),
					recursive);
	}

	private void performOUTM(TupleOp to, Location[] wheretos, boolean recursive) {
		LimeServerID[] targets = null;
		if (wheretos != null) {
			// convert Location array to LimeServerID
			// BTW, why Location and LimeserverID are separated?? Necessary?
			targets = new LimeServerID[wheretos.length];
			for (int i = 0; i < wheretos.length; i++) {
				targets[i] = wheretos[i].getID();
			}
		}

		cMgr.postOp(new RemTupleOp(REM_OUT_MULTI, OPEN, name, targets, to),
				recursive);
	}

	/**
	 * @param to
	 * @param target
	 * @param recursive
	 * @author Xing Jiankuan
	 */
	private void performING(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			to.result.set(ltsm.doTakeg(to.tuples[0]));
			to.result.lock.release();
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			ITuple[] takens = ltsm.doTakeg(to.tuples[0]);
			if (takens != null) {
				ITuple[] tmp = new ITuple[takens.length + 1];
				tmp[0] = to.tuples[0];
				for (int i = 0; i < takens.length; i++)
					tmp[i + 1] = takens[i];
				to.tuples = tmp;
			}
			cMgr.postOp(new RemTupleOp(REM_ING_MULTI, OPEN, name, to),
					recursive);
		}
		// -------------
		// REMOTE CASE
		// -------------
		else
			cMgr.postOp(new RemTupleOp(REM_ING_UNI, OPEN, name, target.getID(),
					to), recursive);
	}

	/**
	 * @param to
	 * @param target
	 * @param recursive
	 * @author Xing Jiankuan
	 */
	private void performINP(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			to.result.set(ltsm.doTake(to.tuples[0]));
			to.result.lock.release();
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			ITuple taken = ltsm.doTake(to.tuples[0]);
			if (taken != null) {
				to.result.set(taken);
				to.result.lock.release();
			} else
				cMgr.postOp(new RemTupleOp(REM_INP_MULTI, OPEN, name, to),
						recursive);
		}
		// -------------
		// REMOTE CASE
		// -------------
		else
			cMgr.postOp(new RemTupleOp(REM_INP_UNI, OPEN, name, target.getID(),
					to), recursive);
	}

	/**
	 * @param to
	 * @param target
	 * @param recursive
	 * @author Xing Jiankuan
	 */
	private void performRDG(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			to.result.set(ltsm.doReadg(to.tuples[0]));
			to.result.lock.release();
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			ITuple[] reads = ltsm.doReadg(to.tuples[0]);
			if (reads != null) {
				ITuple[] tmp = new ITuple[reads.length + 1];
				tmp[0] = to.tuples[0];
				for (int i = 0; i < reads.length; i++)
					tmp[i + 1] = reads[i];
				to.tuples = tmp;
			}
			cMgr.postOp(new RemTupleOp(REM_RDG_MULTI, OPEN, name, to),
					recursive);
		}
		// -------------
		// REMOTE CASE
		// -------------
		else if (LimeSystemTupleSpace.isEngaged(target))
			cMgr.postOp(new RemTupleOp(REM_RDG_UNI, OPEN, name, target.getID(),
					to), recursive);
	}

	/**
	 * @param to
	 * @param recursive
	 * @param engaged
	 * @author Xing Jiankuan
	 */
	private void performRDP(TupleOp to, Location target, boolean recursive) {
		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			to.result.set(ltsm.doRead(to.tuples[0]));
			to.result.lock.release();
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			ITuple read = ltsm.doRead(to.tuples[0]);
			if (read != null) {
				to.result.set(read);
				to.result.lock.release();
			} else
				cMgr.postOp(new RemTupleOp(REM_RDP_MULTI, OPEN, name, to),
						recursive);
		}
		// -------------
		// REMOTE CASE
		// -------------

		else {
			// if(LimeSystemTupleSpace.isEngaged(target)) {
			cMgr.postOp(new RemTupleOp(REM_RDP_UNI, OPEN, name, target.getID(),
					to), recursive);
			// } else {
			// to.result.set(null);
			// to.result.lock.release();
			// }
		}
	}

	/**
	 * @param to
	 * @param recursive
	 * @param engaged
	 * @author Xing Jiankuan
	 */
	private void performRD(TupleOp to, Location target, boolean recursive) {

		// ------------
		// LOCAL CASE
		// ------------
		if (target.isHere()) {
			Reaction[] rrd = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemLocalBlocking(ltsm, to)) };
			ltsm.registerStrong(rrd, ltsm.nextPureStrongRID(1));
		}
		// ------------------
		// UNSPECIFIED CASE
		// ------------------
		else if (target.isUnspecified()) {
			ReactionID[] iS = ltsm.nextStrongRID(1);
			Reaction[] LS = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteBlockingLS(RD, iS[0], ltsm,
							to.result)) };
			Reaction[] LW = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteBlockingLW(true, iS[0], ltsm,
							to.result)) };
			Reaction[] RS = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteWeakR(REM_RDW, name,
							Location.HERE.getID(), iS[0])) };
			ReactionID[] iW = ltsm.createWeakRID(iS, RS);

			ltsm.registerWeak(LW, iW);
			ltsm.registerStrong(LS, iS); // we register LS after LW so
			// that LW will be
			// immediately uninstalled
			// if LS fires

			ReactionOp ro = new ReactionOp(to.type, RS, iS, new Result()); // new
																			// result..
																			// we
																			// don't
																			// want
																			// the
			// older one to be notified
			cMgr.postOp(new RemReactionOp(REM_INSTALL_MULTI, OPEN, name, ro),
					recursive); // recursive is false
		}
		// -------------
		// REMOTE CASE
		// -------------
		else {
			ReactionID[] iS = ltsm.nextStrongRID(1);
			Reaction[] LW = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteBlockingLW(false, iS[0],
							ltsm, to.result)) };
			Reaction[] RS = new Reaction[] { new Reaction(Reaction.ONCE,
					to.tuples[0], new SystemRemoteWeakR(REM_RDW, name,
							Location.HERE.getID(), iS[0])) };
			ReactionID[] iW = ltsm.createWeakRID(iS, RS);

			ltsm.registerWeak(LW, iW);

			ReactionOp ro = new ReactionOp(to.type, RS, iS, new Result()); // new
																			// result..
																			// we
																			// don't
																			// want
																			// the
			// older one to be notified
			cMgr.postOp(new RemReactionOp(REM_INSTALL_UNI, OPEN, name, target
					.getID(), ro), recursive); // recursive is
			// false
		}
	}

	// checks whether the current thread is the Lime system or just an agent
	static boolean isLimeSystem() {
		Thread t = Thread.currentThread();
		if (t instanceof LocalOpMgr || t instanceof ThreadPool.Worker)
			return true;
		else
			return false;
	}

	/**
	 * This method is provided only because of WeakLimeHTTP.
	 * 
	 * Returns textual representation of all the registered reactions. Please
	 * note that since we don't trust classes outside the core of Lime, we
	 * return only textual representation of internal "critical" objects.
	 * 
	 * @return textual representation of the reactions
	 */
	String[] getTextualRegisteredReactions() {
		RegisteredReaction[] r1 = ltsm.getAllStrong();
		RegisteredReaction[] r2 = ltsm.getAllWeak();
		String[] ret = new String[r1.length + r2.length];
		for (int i = 0; i < r1.length; i++)
			ret[i] = LimeHTTP.toFineString(r1[i]);
		for (int i = 0; i < r2.length; i++)
			ret[i + r1.length] = LimeHTTP.toFineString(r2[i]);
		return ret;
	}

}
